<?php

namespace App\Model;

use App\Job\PushOrder;
use App\Services\AdapayService;
use App\Services\Iot\IotService1 as IotService;
use Carbon\Carbon;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Context\ApplicationContext;
use Hyperf\Database\Model\Relations\BelongsTo;
use Hyperf\Utils\Arr;
use Util\Common;

/**
 * App\Order
 *
 * @property int $id
 * @property int $device_id 设备编号
 * @property string $number 订单号
 * @property string $sn 设备编号
 * @property string $payment_type 订单类型
 * @property int $channel_number 通道号
 * @property int $station_id 站点id
 * @property int $user_id 用户
 * @property \Carbon\Carbon|null $estimate_stop_at 预选停止时间
 * @property int|null $duration_seconds 使用时长 秒
 * @property int|null $platform_profit 平台收益
 * @property \Carbon\Carbon|null $stop_at 停止时间
 * @property string|null $stop_reason 停止原因
 * @property string $status 状态
 * @property string|null $result 结果
 * @property-read \App\Model\Device $device
 * @property-read \App\Model\Feedback $feedback
 * @property-read \App\Model\Station $station
 * @property-read \App\Model\User $user
 * @property-read \App\Model\CouponRecord $couponRecord
 */
class Order extends Model
{

    public bool $timestamps = true;
    protected ?string $table = 'orders';


    public static array $paymentTypeMap = [
        Bill::PAYMENT_TYPE_WE_CHAT_PAY => '微信支付',
        Bill::PAYMENT_TYPE_ALI_PAY => '支付宝支付',
        Bill::PAYMENT_TYPE_BALANCE => '余额',
        Bill::PAYMENT_TYPE_IC_CARD => '刷卡',
    ];

    protected array $casts = [
        'estimate_stop_at' => 'datetime',
        'stop_at' => 'datetime',
        'extra' => 'json',
    ];
    protected array $fillable = [
        'device_id', 'number', 'sn', 'user_id', 'payment_type',
        'channel_number', 'station_id', 'fee', 'minutes',
        'estimate_stop_at', 'estimate_minutes', 'platform_profit',
        'stop_at', 'return_fee', 'is_return_fee', 'duration_seconds',
        'stop_reason', 'status', 'extra', 'electric_quantity', 'power',
        'coupon_record_id', 'original_fee', 'surplus_electricity',
        'is_fail', 'service_id', 'service_fee', 'power_fee', 'is_draw', 'charge_service',
        'is_autoload', 'charge_id', 'charge_detail_id', 'out_ord_id', 'use_elec', 'use_fee',
        'pay_at', 'refund_at', 'payment_id', 'is_check', 'distributor_id', 'is_disabled'
    ];

    const FREE_SECONDS = 420;

//    //最长充电时长
//    const MAX_HOURS = 8;

    const RETURN = 1;
    const UNRETURN = 0;

    const STATUS_UNPAID = 'unpaid';
    const STATUS_PAID = 'paid';
    const STATUS_USING = 'using';
    const STATUS_END = 'end';
    const STATUS_FAILED = 'failed';
    const STATUS_REFUNDED = 'refunded';
    const STATUS_PAY_TIMEOUT = 'timeout';

    const STATUS_MAP = [
        self::STATUS_UNPAID => '未支付',
        self::STATUS_PAID => '已支付',
        self::STATUS_USING => '使用中',
        self::STATUS_END => '已完成',
        self::STATUS_FAILED => '失败',
        self::STATUS_REFUNDED => '已退款',
        self::STATUS_PAY_TIMEOUT => '支付超时'
    ];

    //关联的账单类型
    const RELATE_BILL_TYPE_MAP = [
        Bill::TYPE_ORDER_PAY,
        Bill::TYPE_DISTRIBUTOR_ORDER_PROFIT,
        Bill::TYPE_DISTRIBUTOR_DIRECT_ORDER_PROFIT,
        Bill::TYPE_PLATFORM_PROFIT,
    ];

    const SUCCESS_REFUND = 1;
    const NORMAL_REFUND = 0;

    public function feedback()
    {
        return $this->hasOne(Feedback::class);
    }

    public function charge(): BelongsTo
    {
        return $this->belongsTo(ChargeOption::class, 'charge_id', 'id');
    }

    public function station(): BelongsTo
    {
        return $this->belongsTo(Station::class, 'station_id', 'id');
    }

    public function chargeDetail(): BelongsTo
    {
        return $this->belongsTo(ChargeDetail::class, 'charge_detail_id', 'id');
    }

    public function device(): BelongsTo
    {
        return $this->belongsTo(Device::class, 'device_id', 'id');
    }

    public function order(): BelongsTo
    {
        return $this->belongsTo(Distributors::class, 'distributor_id', 'id');
    }


    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    public function couponRecord(): BelongsTo
    {
        return $this->belongsTo(CouponRecord::class, 'coupon_record_id', 'id');
    }


    //
    public function getDurationSeconds()
    {
        //使用中的为空
        if ($this->status != self::STATUS_USING && $this->status != self::STATUS_PAID) {
            return $this->duration_seconds ?? 0;
        }

        return Carbon::now()->timestamp - $this->created_at->timestamp;
    }

    public function getNormalTime(int $power, int $chargeOptionId)
    {
        $chargeDetail = ChargeDetail::where('charge_option_id', $chargeOptionId)
            ->where('type', ChargeDetail::POWER_TYPE)
            ->where('min_power', '>=', $power)
            ->where('max_power', '<=', $power)
            ->first();
        return $chargeDetail;
    }


    public function getStatusDes()
    {
        return Arr::get(self::STATUS_MAP, $this->status);
    }


    public function getPaymentTypeDes()
    {
        return Arr::get(self::$paymentTypeMap, $this->payment_type);
    }

    //是否需要通知设备停止
    public function stop($reason, $surplusElectric, $notifyDevice = false)
    {
        //这里有默认值的坑 新添加的数据 是数据库赋予的默认值 但是创建后立即对模型进行默认值字段的值判断 会出现问题 模型上改字段为null 但实际数据库中字段为默认值的问题 造成判断错误
        if (!is_null($this->status) && $this->status != self::STATUS_USING && $this->status != self::STATUS_PAID) {
            return '';
        }
        if($this->device->is_new == 1 && $notifyDevice == true && $this->charge->type == 3){
            IotService::stop($this->device->iot_sn, $this->channel_number);
            return '';
        }
        $this->duration_seconds = $this->getDurationSeconds();
        $this->status = self::STATUS_END;
        $this->stop_at = Carbon::now();
        $this->stop_reason = $reason;
        $this->surplus_electricity = $surplusElectric;
        $device = $this->device;
        $seconds = $this->minutes * 60;
        if ($this->charge->type == 3) {
//            if ($device->is_new == 1) {
//                $this->use_elec = $surplusElectric * 10;
//            }
            //长时间费用为零元的情况
            if ($this->use_fee <= 0 && $this->charge_service <= 0) {
                if ($this->power <= 0) {
                    $this->power = rand(200, 400);
                }
                $use_elec = ($this->power * $this->duration_seconds) / 3600;
                $this->use_elec = rand($use_elec, 2);
                if ($this->charge->service_type == 1) {
                    $powerFee = ($this->use_elec / 1000) * $this->charge->elec_price;
                    $chargeService = ($this->use_elec / 1000) * $this->charge->service_fee;
                    $this->charge_service = number_format($chargeService, 2, '.', '');
                    $this->use_fee = number_format($powerFee, 2, '.', '');
                } else {
                    $hours = $seconds/3600;
                    $powerFee = ($this->use_elec / 1000) * $this->charge->elec_price;
                    $detailList = ChargeDetail::where('charge_option_id',$this->charge->id)
                        ->where('type',ChargeDetail::SERVICE_TYPE)
                        ->where('is_del',1)
                        ->get()->toArray();
                    $serviceFee = $this->charge->service_fee;
                    foreach ($detailList as $k => $v) {
                        if ($this->power >= $v['min_power'] && $this->power <= $v['max_power']) {
                            $serviceFee = $v['fee'];
                            break;
                        }
                    }
                    $chargeService = $serviceFee*$hours;
                    $this->charge_service = number_format($chargeService,2,'.','');
                    $this->use_fee = number_format($powerFee,2,'.','');
                }
            }
            //结束模拟假数据
            if ($this->original_fee > $this->use_fee + $this->charge_service && ($device->is_refund > 0 || $this->is_autoload == 1)) {
                $this->return_fee = $this->original_fee - $this->use_fee - $this->charge_service;
                if ($this->coupon_record_id) {
                    $use_fee = $this->use_fee + $this->charge_service;
                    $decr_fee = $this->original_fee - $this->power_fee;
                    if ($decr_fee > $use_fee) {
                        $this->return_fee = $this->power_fee;
                    }
                }
                if ($this->return_fee >= $this->power_fee) {
                    $this->return_fee = $this->power_fee;
                }
                if ($this->return_fee < 0) {
                    $this->return_fee = 0;
                }
            } else {
                $this->return_fee = 0;
            }

        } else {
            if($this->device->is_new == 1 && $this->charge->is_autoload == 1){
                if($this->power <= 0) {
                    $this->power = rand(200, 400);
                }
                   $chargeDetail =  ChargeDetail::query()->where('charge_option_id',$this->charge_id)
                        ->where('type',ChargeDetail::POWER_TYPE)
                        ->where('min_power','<=',$this->power)
                        ->where('max_power','>=',$this->power)
                        ->first();
                   if($chargeDetail){
                       $seconds = $this->power_fee*$chargeDetail->minutes*60;
                   }else{
                       $seconds = $this->power_fee*240*60;
                   }
            }
            //      if($seconds > $this->duration_seconds && $this->is_autoload == 1) { //根据套餐
            if ($seconds > $this->duration_seconds && ($device->is_refund > 0 || $this->is_autoload == 1)) { //根据设备状态
                $this->return_fee = number_format((($seconds - $this->duration_seconds) / $seconds) * $this->original_fee, 2, '.', '');
                if ($this->coupon_record_id) {
                    $use_fee = ($this->duration_seconds / $seconds) * $this->original_fee;
                    $decr_fee = $this->original_fee - $this->power_fee;
                    if ($decr_fee > $use_fee) {
                        $this->return_fee = $this->power_fee;
                    }
                }
                if ($this->return_fee < 0) {
                    $this->return_fee = 0;
                }
                if ($this->return_fee >= $this->power_fee) {
                    $this->return_fee = $this->power_fee;
//                $couponRecord = $this->couponRecord;
//                $couponRecord && $couponRecord->markAsUnused();
                }
            } else {
                $this->return_fee = 0;
            }
        }
        if($this->power_fee-$this->return_fee < $this->charge->pre_fee){
            $this->return_fee = $this->power_fee-$this->charge->pre_fee;
            if($this->return_fee < 0){
                $this->return_fee = 0;
            }
        }
        $this->return_fee = number_format($this->return_fee, 2, '.', '');
        try {
            if ($this->payment_type == Bill::PAYMENT_TYPE_BALANCE) {
                $this->user->decrementBalance($this->fee - $this->return_fee);
                Bill::record(
                    $this->user,
                    -($this->fee - $this->return_fee),
                    Bill::TYPE_ORDER_PAY,
                    Bill::PAYMENT_TYPE_BALANCE,
                    $this->id
                );
                $this->is_return_fee = self::RETURN;
            }
            if ($device->is_refund > 0 || $this->is_autoload == 1) {
                if ($this->return_fee > 0) {
                    if ($this->payment_type == Bill::PAYMENT_TYPE_BALANCE) {

                    } else {
                        $refoundParams = array(
                            "payment_id" => $this->payment_id,
                            # 退款订单号
                            "refund_order_no" => $this->number,
                            # 退款金额
                            "refund_amt" => $this->return_fee,
                            "notify_url" => Common::MAIN_HOST . '/user/order/refund'
                        );
                        $adapayService = new AdapayService();
                        $adapayService->refundPayment($refoundParams);
//                        $this->status =self::STATUS_REFUNDED;
                    }
                }
            }
            $this->distributorSettle();
        } catch (\Exception $e) {
            Normal::logger($this->id . '结算失败: ' . $e->getMessage(), 'order-event');
        }

        //单次刷卡最大用电量 单位为0.1/元 减去剩余电量则为实际电量(传入的电量实际为剩余电量) 所以销售的电量减去剩余电量就是实际使用的电量
//        $realElectric = $device->card_elec * 0.1 * $this->original_fee  - $this->surplus_electricity;
//        $this->electric_quantity = max($realElectric, 0);
        $this->save();
        if ($this->device->port_status) {
            $port_status = $this->device->port_status;
            foreach ($port_status as $k => &$v) {
                if ($v['number'] == $this->channel_number) {
                    $v['status'] = 1;
                    break;
                }
            }
            $this->device->port_status = $port_status;
            $this->device->save();

        }
        if ($notifyDevice) {
            IotService::stop($device->iot_sn, $this->channel_number);
        }
        if (!$this->is_draw) {
//            if($this->distributor_id == 237){
            $this->feeStatics();
//            }
        }


        if($this->needPush() && $this->charge->type == 3){
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('push-order');
            $driver->push(new PushOrder($this->id,'end'),30);
        }

        //结算
//        $this->settlement();

//        //更新设备参数 以此来计算电量
//        $device->updateParams();

//        //发送消息
//        $user = $this->user;

//        switch ($user->source)
//        {
//            case User::SOURCE_WE_CHAT:
//                //发送消息
//                $message = new Text("您好：充电已停止，请确认！安全充电，人人有责！");
//                $res = WechatService::getApp()->customer_service->message($message)->to($user->openid)->send();
//                logger('send text message', [
//                    'order_id' => $this->id,
//                    'openid' => $user->openid,
//                    'res' => $res,
//                ]);
//
//                break;
//        }

    }

    /**将数据同步给缓存进行统计
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function feeStatics()
    {
        try {
            $date = date('Y-m-d', time());
            if ($this->device->child_distributor_id > 0) {
                $countKey = 'DISTRIBUTOR_ORDER_COUNT' . $date . '_' . $this->device->child_distributor_id;
                if ($this->is_disabled != 1) {
                    $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $this->device->distributor_id;
                    $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $this->device->distributor_id;
                    if (!redis()->exists($powerKey)) {
                        $devices = Device::where('distributor_id', $this->device->distributor_id)
                            ->get(['id']);
                        $indDevices = [];
                        foreach ($devices as $v) {
                            $indDevices[] = $v['id'];
                        }
                        $status = [Order::STATUS_END, Order::STATUS_REFUNDED];
                        $powerFee = Order::whereIn('device_id', $indDevices)
                            ->whereIn('status', $status)
                            ->where('is_draw', 0)
                            ->where('is_disabled', 0)
                            ->sum('power_fee');
                        redis()->set($powerKey, $powerFee);
                        $returnFee = Order::whereIn('device_id', $indDevices)
                            ->where('is_return_fee', 1)
                            ->where('is_draw', 0)
                            ->where('is_disabled', 0)
                            ->sum('return_fee');
                        redis()->set($returnKey, $returnFee);
                    } else {
                        redis()->incrByFloat($powerKey, (float)$this->power_fee);
                        redis()->incrByFloat($returnKey, (float)$this->return_fee);
                    }
                    $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $date . '_' . $this->device->distributor_id;
                    $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $date . '_' . $this->device->distributor_id;
                    if (redis()->exists($powerKey)) {
                        redis()->incrByFloat($powerKey, (float)$this->power_fee);
                        redis()->incrByFloat($returnKey, (float)$this->return_fee);
                    } else {
                        redis()->setex($powerKey, 60 * 60 * 24, $this->power_fee);
                        redis()->setex($returnKey, 60 * 60 * 24, $this->return_fee);
                    }
                }

                $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $this->device->child_distributor_id;
                $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $this->device->child_distributor_id;
                if (!redis()->exists($powerKey)) {
                    $devices = Device::where('child_distributor_id', $this->device->child_distributor_id)
                        ->get(['id']);
                    $indDevices = [];
                    foreach ($devices as $v) {
                        $indDevices[] = $v['id'];
                    }
                    $status = [Order::STATUS_END, Order::STATUS_REFUNDED];
                    $powerFee = Order::whereIn('device_id', $indDevices)
                        ->whereIn('status', $status)
                        ->where('is_draw', 0)
                        ->where('is_disabled', 0)
                        ->sum('power_fee');
                    redis()->set($powerKey, $powerFee);
                    $returnFee = Order::whereIn('device_id', $indDevices)
                        ->where('is_return_fee', 1)
                        ->where('is_draw', 0)
                        ->where('is_disabled', 0)
                        ->sum('return_fee');
                    redis()->set($returnKey, $returnFee);
                } else {
                    redis()->incrByFloat($powerKey, (float)$this->power_fee);
                    redis()->incrByFloat($returnKey, (float)$this->return_fee);
                }
                $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $date . '_' . $this->device->child_distributor_id;
                $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $date . '_' . $this->device->child_distributor_id;
                if (redis()->exists($powerKey)) {
                    redis()->incrByFloat($powerKey, (float)$this->power_fee);
                    redis()->incrByFloat($returnKey, (float)$this->return_fee);
                } else {
                    redis()->setex($powerKey, 60 * 60 * 24, (float)$this->power_fee);
                    redis()->setex($returnKey, 60 * 60 * 24, (float)$this->return_fee);
                }

            } else {
                $countKey = 'DISTRIBUTOR_ORDER_COUNT' . $date . '_' . $this->device->distributor_id;
                $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $this->device->distributor_id;
                $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $this->device->distributor_id;
                if (!redis()->exists($powerKey)) {
                    $devices = Device::where('distributor_id', $this->device->distributor_id)
                        ->get(['id']);
                    $indDevices = [];
                    foreach ($devices as $v) {
                        $indDevices[] = $v['id'];
                    }
                    $status = [Order::STATUS_END, Order::STATUS_REFUNDED];
                    $powerFee = Order::whereIn('device_id', $indDevices)
                        ->whereIn('status', $status)
                        ->where('is_draw', 0)
                        ->where('is_disabled', 0)
                        ->sum('power_fee');
                    redis()->set($powerKey, $powerFee);
                    $returnFee = Order::whereIn('device_id', $indDevices)
                        ->where('is_return_fee', 1)
                        ->where('is_draw', 0)
                        ->where('is_disabled', 0)
                        ->sum('return_fee');
                    redis()->set($returnKey, $returnFee);
                } else {
                    redis()->incrByFloat($powerKey, (float)$this->power_fee);
                    redis()->incrByFloat($returnKey, (float)$this->return_fee);
                }
                $powerKey = 'DISTRIBUTOR_ORDER_POWER_' . $date . '_' . $this->device->distributor_id;
                $returnKey = 'DISTRIBUTOR_ORDER_RETURN_' . $date . '_' . $this->device->distributor_id;
                if (redis()->exists($powerKey)) {
                    redis()->incrByFloat($powerKey, (float)$this->power_fee);
                    redis()->incrByFloat($returnKey, (float)$this->return_fee);
                } else {
                    redis()->setex($powerKey, 60 * 60 * 24, (float)$this->power_fee);
                    redis()->setex($returnKey, 60 * 60 * 24, (float)$this->return_fee);
                }
            }
            if (redis()->exists($countKey)) {
                redis()->incr($countKey);
            } else {
                redis()->setex($countKey, 60 * 60 * 24, 1);
            }
        } catch (\Exception $e) {
            Normal::logger($this->id . '统计失败: ' . $e->getMessage(), 'order-event');
        }
    }


    public function getStopReason()
    {
        $reason = $this->stop_reason;

        if ($reason == "超时未充电或用户手动停止") {
            $reason = "充电异常，已退款！请检查或更换插座重试！";
        }

        return $reason;
    }


    public function startSuccess()
    {
        $this->status = self::STATUS_USING;
        $this->save();
    }


    public function fail($reason, $notifyDevice = false)
    {
        $this->duration_seconds = $this->getDurationSeconds();
        $this->status = self::STATUS_FAILED;
        $this->stop_at = Carbon::now();
        $this->stop_reason = $reason;
        $this->save();
        if ($this->device->port_status) {
            $port_status = $this->device->port_status;
            foreach ($port_status as $k => &$v) {
                if ($v['number'] == $this->channel_number) {
                    $v['status'] = 1;
                    break;
                }
            }
            $this->device->port_status = $port_status;
            $this->device->save();
        }
        try {
            //有优惠卷就标记为未使用
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUnused();
            $this->refund();
            if ($notifyDevice) {
                IotService::stop($this->device->iot_sn, $this->channel_number);
            }
        } catch (\Exception $exception) {
            Normal::logger($this->id . '退款失败: ' . $exception->getMessage(), 'order-event');
        }
    }


    public function balancePay(array $extra = [])
    {
        $config = [
            'code' => 200,
            'need_pay' => false,
            'number' => $this->number
        ];
        if ($this->fee <= 0) {
            $this->paySuccess();
            return $config;
        }
        $user = $this->user;
        switch ($this->payment_type) {
            case Bill::PAYMENT_TYPE_BALANCE:
                if (!$user) {
                    return array('code' => 1001, 'msg' => '用户不存在');
                }
                if ($this->fee > $user->getTotalBalance()) {
                    return array('code' => 1001, 'msg' => '余额不足');
                }
                if ($this->service_id) {
//                    $user->decrementBalance($this->service_fee);
                    $user->upVip($this->service_id);
                }
                $bool = $this->checkDraw();
                $this->incrDrawNumber();
                if ($bool) {
                    $this->drawOrder();
                }
                $this->paySuccess();
                break;
            default:
                //...
        }
        return $config;
    }

    public function checkDraw(): bool
    {
        $distributor = Distributors::where('id', $this->distributor_id)->first();
        $cacheKey = 'DRAW_DISTRIBUTOR_' . $this->distributor_id;
        if ($distributor->draw_active) {
            if (redis()->exists($cacheKey)) {
                $drawCount = redis()->get($cacheKey);
                if ($drawCount >= $distributor->draw_space) {
                    return true;
                }
            } else {
                redis()->set($cacheKey, 0);
                return false;
            }
        }
        return false;
    }

    public function incrDrawNumber()
    {
        $cacheKey = 'DRAW_DISTRIBUTOR_' . $this->distributor_id;
        redis()->incr($cacheKey);
    }

    /**
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function drawOrder()
    {
        $cacheKey = 'DRAW_DISTRIBUTOR_' . $this->distributor_id;
        $this->is_draw = 1;
        redis()->del($cacheKey);
    }

    /**支付宝微信支付回调
     * @param array $params
     * @return void
     */
    public function payMent(array $params)
    {
        if ($params['status'] == 'succeeded') {
            $this->status = self::STATUS_PAID;
            $this->pay_at = $params['end_time'];
            $this->payment_id = $params['id'];
            $this->out_ord_id = $params['out_trans_id'];
            $bool = $this->checkDraw();
            $this->incrDrawNumber();
            if ($bool) {
                $this->drawOrder();
            }
            $this->paySuccess();
            if ($this->service_id) {
                $this->user->upVip($this->service_id);
            }
//            PaymentOrder::create([
//                    'number' => $params['id'],
//                    'user_id'=>$this->user_id,
//                    'fee'=>$this->fee,
//                    'payment_type'=>$this->payment_type,
//                    'type'=>'pay',
//                    'paid_at'=>$params['end_time'],
//                    'target_id'=>$this->id,
//                    'extra'=>json_encode($params),
//                    'status' =>$params['status'],
//                    'out_ord_id'=>$params['out_trans_id'],
//                    'payment_id'=>$params['id']
//                ]);
        } else {
            $this->status = self::STATUS_PAY_TIMEOUT;
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUnused();
            $this->save();
//            PaymentOrder::create([
//                'number' => $params['id'],
//                'user_id'=>$this->user_id,
//                'fee'=>$this->fee,
//                'payment_type'=>$this->payment_type,
//                'type'=>'pay',
//                'target_id'=>$this->id,
//                'extra'=>json_encode($params),
//                'status' =>$params['status'],
//                'out_ord_id'=>$params['out_trans_id']
//            ]);
        }
    }

    public function paySuccess()
    {
        $this->estimate_stop_at = Carbon::now();
        $this->estimate_minutes = time();
        $device = $this->device;
        //尝试开始充电
        try {
            $this->status = self::STATUS_PAID;
            $this->save();
            //尝试开始充电
            if ($this->charge->type == 3) {
                if ($this->is_autoload) {
                    $mode = 4;//自停
                    $elec = $this->charge->elec * 100;

                } else {
                    $mode = 1;//电量倒计时
                    $elec = 200;
                }
                if($device->is_new == 1){
                    $device->startNew($this->channel_number,$this->charge,$this->original_fee,$this->minutes,$device->speed);
                }else{
                    $device->start($this->channel_number, $this->minutes, $this->original_fee, $elec, $mode);
                }
            } else {
                $mode = 1;//自停
                if($device->is_new == 1){
                    $device->startNew($this->channel_number,$this->charge,$this->original_fee,$this->minutes,$device->speed);
                }else{
                    $device->start($this->channel_number, $this->minutes, $this->original_fee, 200, $mode);
                }
            }
//            logger('order pay success ' . $this->id);
            if ($this->device->port_status) {
                $port_status = $this->device->port_status;
                foreach ($port_status as $k => &$v) {
                    if ($v['number'] == $this->channel_number) {
                        $v['status'] = 2;
                        break;
                    }
                }
                $this->device->port_status = $port_status;
                $this->device->save();
            }
            //有优惠卷就标记为已使用
            $couponRecord = $this->couponRecord;
            $couponRecord && $couponRecord->markAsUsed();
            if($this->needPush() && $this->charge->type == 3){
                $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('push-order');
                $driver->push(new PushOrder($this->id));
            }
        } catch (\Exception $exception) {
            $message = $exception->getMessage();
            //标记为租用失败
            $this->fail($message);
        }
    }

    public function checkCanRefund()
    {
        //完成的订单和失败的才能退款
        if (!in_array($this->status, [
            self::STATUS_FAILED,
            self::STATUS_END,
            self::STATUS_PAID
        ])) {
            return false;
        }

        //有用户的订单都表示是线上支付的 就可以退
        if (!$this->user) {
            return false;
        }

        return true;
    }

    /**安心充退款
     * @return string|void
     */
    public function serviceRefund()
    {
        if ($this->status == self::STATUS_UNPAID && $this->service_fee <= 0) {
            return '';
        }
        switch ($this->payment_type) {
            //支付宝支付退回
            case Bill::PAYMENT_TYPE_ALI_PAY:
                //微信支付退回
            case Bill::PAYMENT_TYPE_WE_CHAT_PAY:
                $refoundParams = array(
                    "payment_id" => $this->payment_id,
                    # 退款订单号
                    "refund_order_no" => 'SV' . $this->number,
                    # 退款金额
                    "refund_amt" => $this->service_fee,
                    "notify_url" => Common::MAIN_HOST . '/user/order/refund_service'
                );
                $adapayService = new AdapayService();
                $adapayService->refundPayment($refoundParams);
                break;
            default:
                $this->return_fee += $this->service_fee;
                $this->service_fee = 0;
                $this->save();
                $this->user->refundStatus($this->service_id);
                break;
        }
    }

    /**退款成功后业务
     * @param $params
     * @return void
     */
    public function serviceRefundSuccess($params)
    {
        $this->return_fee += $params['refund_amt'];
//      $this->return_fee += $params['refund_amt']-$params['fee_amt'];
        $this->service_fee = 0;
        $this->save();
        $this->user->refundStatus($this->service_id);
    }

    /**自定义退款
     * @param $params
     * @return void
     */
    public function normalRefundSuccess($params)
    {
        $fee = $params['refund_amt'];
        $need = true;
        if($this->return_fee == 0){
            $bills = Bill::where('target_id',$this->id)->first();
            if($bills){
                $all_return_fee = $this->power_fee-$bills->fee;
                if($fee <= $all_return_fee){
                    $need = false;
                }else{
                    $diffFee = $fee-$all_return_fee;
                }
            }
        }
        $this->return_fee += $fee;
        $this->is_return_fee = 1;
        $this->save();
        if($need == false){
            Normal::logger('无需重复扣减商户----','order-event');
        }else{
            $fee = $diffFee;
        }
        $deviceModel = Device::where('id', $this->device_id)->first();
        $firstDis = Distributors::where('id', $deviceModel->distributor_id)
            ->first();
        if ($deviceModel->child_distributor_id) {
            $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                ->first();
            $disMoney = number_format($fee * $childDis->rate / 100, 2);
            $childDis->balance -= $disMoney;
            $childDis->save();
            $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
                ->where('device_id', $this->device_id)
                ->first();
            if ($distributorDevice) {
                $distributorDevice->profit -= $disMoney;
                $distributorDevice->save();
            } else {
                $profit['profit'] = -$disMoney;
                $profit['distributor_id'] = $childDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
            }
            $bills = Bill::where('target_id', $this->id)
                ->where('account_id', $deviceModel->child_distributor_id)
                ->first();
            if ($bills) {
                $bills->fee -= $disMoney;
                $bills->balance -= $disMoney;
                $bills->save();
            }
            if ($firstDis->rate > $childDis->rate) {
                $firstRate = $firstDis->rate - $childDis->rate;
                if ($firstRate > 0) {
                    $firstMoney = number_format($fee * $firstRate / 100, 2);
                    $firstDis->balance -= $firstMoney;
                    $firstDis->save();
                    $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                        ->where('device_id', $this->device_id)
                        ->first();
                    if ($distributorDevice) {
                        $distributorDevice->profit -= $firstMoney;
                        $distributorDevice->save();
                    } else {
                        $profit['profit'] = -$firstMoney;
                        $profit['distributor_id'] = $firstDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                    }
                    $bills = Bill::where('target_id', $this->id)
                        ->where('account_id', $deviceModel->distributor_id)
                        ->first();
                    if ($bills) {
                        $bills->fee -= $firstMoney;
                        $bills->balance -= $firstMoney;
                        $bills->save();
                    }
                }
            }
        } else {
            $firstMoney = number_format($fee * $firstDis->rate / 100, 2);
            $firstDis->balance -= $firstMoney;
            $firstDis->save();
            $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                ->where('device_id', $this->device_id)
                ->first();
            if ($distributorDevice) {
                $distributorDevice->profit -= $firstMoney;
                $distributorDevice->save();
            } else {
                $profit['profit'] = -$firstMoney;
                $profit['distributor_id'] = $firstDis->id;
                $profit['device_id'] = $this->device_id;
                DistributorDevice::create($profit);
            }
            $bills = Bill::where('target_id', $this->id)
                ->where('account_id', $deviceModel->distributor_id)
                ->first();
            if ($bills) {
                $bills->fee -= $firstMoney;
                $bills->balance -= $firstMoney;
                $bills->save();
            }
        }
    }

    /**自定义退款操作
     * @param $fee
     * @return string|void
     */
    public function normalRefund($fee)
    {
        if ($this->status != self::STATUS_END && $this->status != self::STATUS_REFUNDED && $this->status != self::STATUS_FAILED) {
            return '';
        }
        switch ($this->payment_type) {
            //支付宝支付退回
            case Bill::PAYMENT_TYPE_ALI_PAY:
                //微信支付退回
            case Bill::PAYMENT_TYPE_WE_CHAT_PAY:
                $refoundParams = array(
                    "payment_id" => $this->payment_id,
                    # 退款订单号
                    "refund_order_no" => 'NR' . rand(99, 999) . $this->number,
                    # 退款金额
                    "refund_amt" => $fee,
                    "notify_url" => Common::MAIN_HOST . '/user/order/refund_normal'
                );
                $adapayService = new AdapayService();
                $adapayService->refundPayment($refoundParams);
                break;
            default:
                $this->return_fee += $fee;
                $this->save();
                $this->user->balance += $fee;
                $this->user->save();
                $deviceModel = Device::where('id', $this->device_id)->first();
                $firstDis = Distributors::where('id', $deviceModel->distributor_id)
                    ->first();
                if ($deviceModel->child_distributor_id) {
                    $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                        ->first();
                    $disMoney = number_format($fee * $childDis->rate / 100, 2);
                    $childDis->balance -= $disMoney;
                    $childDis->save();
                    $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
                        ->where('device_id', $this->device_id)
                        ->first();
                    if ($distributorDevice) {
                        $distributorDevice->profit -= $disMoney;
                        $distributorDevice->save();
                    } else {
                        $profit['profit'] = -$disMoney;
                        $profit['distributor_id'] = $childDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                    }
                    $bills = Bill::where('target_id', $this->id)
                        ->where('account_id', $deviceModel->child_distributor_id)
                        ->first();
                    if ($bills) {
                        $bills->fee -= $disMoney;
                        $bills->balance -= $disMoney;
                        $bills->save();
                    }
                    if ($firstDis->rate > $childDis->rate) {
                        $firstRate = $firstDis->rate - $childDis->rate;
                        if ($firstRate > 0) {
                            $firstMoney = number_format($fee * $firstRate / 100, 2);
                            $firstDis->balance -= $firstMoney;
                            $firstDis->save();
                            $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                                ->where('device_id', $this->device_id)
                                ->first();
                            if ($distributorDevice) {
                                $distributorDevice->profit -= $firstMoney;
                                $distributorDevice->save();
                            } else {
                                $profit['profit'] = -$firstMoney;
                                $profit['distributor_id'] = $firstDis->id;
                                $profit['device_id'] = $this->device_id;
                                DistributorDevice::create($profit);
                            }
                            $bills = Bill::where('target_id', $this->id)
                                ->where('account_id', $deviceModel->distributor_id)
                                ->first();
                            if ($bills) {
                                $bills->fee -= $firstMoney;
                                $bills->balance -= $firstMoney;
                                $bills->save();
                            }
                        }
                    }
                } else {
                    $firstMoney = number_format($fee * $firstDis->rate / 100, 2);
                    $firstDis->balance -= $firstMoney;
                    $firstDis->save();
                    $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                        ->where('device_id', $this->device_id)
                        ->first();
                    if ($distributorDevice) {
                        $distributorDevice->profit -= $firstMoney;
                        $distributorDevice->save();
                    } else {
                        $profit['profit'] = -$firstMoney;
                        $profit['distributor_id'] = $firstDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                    }
                    $bills = Bill::where('target_id', $this->id)
                        ->where('account_id', $deviceModel->distributor_id)
                        ->first();
                    if ($bills) {
                        $bills->fee -= $firstMoney;
                        $bills->balance -= $firstMoney;
                        $bills->save();
                    }
                }
                break;
        }
    }


    /**常规退款
     * @return string|void
     */
    public function refund()
    {
        if (!$this->checkCanRefund()) {
            return '';
        }

        switch ($this->payment_type) {
            //支付宝支付退回
            case Bill::PAYMENT_TYPE_ALI_PAY:
                //微信支付退回
            case Bill::PAYMENT_TYPE_WE_CHAT_PAY:
                $refoundParams = array(
                    "payment_id" => $this->payment_id,
                    # 退款订单号
                    "refund_order_no" => $this->number,
                    # 退款金额
                    "refund_amt" => $this->power_fee,
                    "notify_url" => Common::MAIN_HOST . '/user/order/refund'
                );
                if ($this->power_fee > 0) {
                    $adapayService = new AdapayService();
                    $adapayService->refundPayment($refoundParams);
                }
                break;
            default:
        }
        $this->is_return_fee = 1;
        $this->return_fee = $this->power_fee;
        $this->status = self::STATUS_REFUNDED;
        $this->save();
//        if($this->service_id){
//            $this->user->decrementBalance($this->service_fee);
//            $this->user->upVip($this->service_id);
//        }
        //有优惠卷就标记为未使用
        $couponRecord = $this->couponRecord;
        $couponRecord && $couponRecord->markAsUnused();
        if($this->needPush() && $this->charge->type == 3){
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('push-order');
            $driver->push(new PushOrder($this->id,'end'),30);
        }
    }

    /**退款分账流水
     * @param $params
     * @return void
     */
    public function refundSuccess($params)
    {
//        if($params['fee_amt']>0){
//            $this->return_fee = $params['refund_amt']-$params['fee_amt'];
//        }else{
        $this->return_fee = $params['refund_amt'];
//        }
        $this->is_return_fee = 1;
        $this->save();
//        if ($params['refund_amt'] < $this->power_fee) {
//            $this->distributorSettle();
//        }
    }

    /**经销商盈利
     * @return void
     */
    public function distributorSettle()
    {
        try {
            if (!$this->is_draw) {
//                $orderMoney = $this->power_fee;
//                if ($this->is_return_fee == self::SUCCESS_REFUND) {
                    $orderMoney = $this->power_fee - $this->return_fee;
//                }
                if ($orderMoney <= 0) {
                    return '';
                }
                $deviceModel = Device::where('id', $this->device_id)->first();
                $firstDis = Distributors::where('id', $deviceModel->distributor_id)
                    ->first();
                if ($deviceModel->child_distributor_id) {
                    $childDis = Distributors::where('id', $deviceModel->child_distributor_id)
                        ->first();
                    $disMoney = number_format($orderMoney * $childDis->rate / 100, 2);
                    $childDis->balance += $disMoney;
                    $childDis->save();
                    $distributorDevice = DistributorDevice::where('distributor_id', $childDis->id)
                        ->where('device_id', $this->device_id)
                        ->first();
                    if ($distributorDevice) {
                        $distributorDevice->profit += $disMoney;
                        $distributorDevice->save();
                    } else {
                        $profit['profit'] = $disMoney;
                        $profit['distributor_id'] = $childDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                    }
                    Bill::record(
                        $childDis,
                        $disMoney,
                        Bill::TYPE_ORDER_PAY,
                        $this->payment_type,
                        $this->id
                    );
                    if ($firstDis->rate > $childDis->rate && $this->is_disabled != 1) {
                        $firstRate = $firstDis->rate - $childDis->rate;
                        if ($firstRate > 0) {
                            $firstMoney = number_format($orderMoney * $firstRate / 100, 2);
                            $firstDis->balance += $firstMoney;
                            $firstDis->save();
                            $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                                ->where('device_id', $this->device_id)
                                ->first();
                            if ($distributorDevice) {
                                $distributorDevice->profit += $firstMoney;
                                $distributorDevice->save();
                            } else {
                                $profit['profit'] = $firstMoney;
                                $profit['distributor_id'] = $firstDis->id;
                                $profit['device_id'] = $this->device_id;
                                DistributorDevice::create($profit);
                            }
                            Bill::record(
                                $firstDis,
                                $firstMoney,
                                Bill::TYPE_ORDER_PAY,
                                $this->payment_type,
                                $this->id
                            );
                        }
                    }
                } else {
                    $firstMoney = number_format($orderMoney * $firstDis->rate / 100, 2);
                    $firstDis->balance += $firstMoney;
                    $firstDis->save();
                    $distributorDevice = DistributorDevice::where('distributor_id', $firstDis->id)
                        ->where('device_id', $this->device_id)
                        ->first();
                    if ($distributorDevice) {
                        $distributorDevice->profit += $firstMoney;
                        $distributorDevice->save();
                    } else {
                        $profit['profit'] = $firstMoney;
                        $profit['distributor_id'] = $firstDis->id;
                        $profit['device_id'] = $this->device_id;
                        DistributorDevice::create($profit);
                    }
                    Bill::record(
                        $firstDis,
                        $firstMoney,
                        Bill::TYPE_ORDER_PAY,
                        $this->payment_type,
                        $this->id
                    );
                }
            }
        } catch (\Exception $e) {
            Normal::logger('error-distributor:'.$e->getMessage().$e->getTraceAsString(),'order-event');
        }
    }

    //结算订单
    public function settlement()
    {
        $billOther = [
            'order_id' => $this->id,
        ];
//        logger('order settlement', [
//            'order_id' => $this->id,
//            'payment_type' => $this->payment_type,
//            'fee' => $this->fee,
//        ]);

        switch ($this->payment_type) {
            case Bill::PAYMENT_TYPE_BALANCE:
            case Bill::PAYMENT_TYPE_ALI_PAY:
            case Bill::PAYMENT_TYPE_WE_CHAT_PAY:

                if ($this->fee > 0) {
                    SettlementDistributorProfit::dispatch($this, Bill::TYPE_ORDER_PAY, $this->fee, null, $billOther);
                }
                break;

            default:
                //....
        }
    }


    public function scopeInUsing($query)
    {
        return $query->where('status', self::STATUS_USING);
    }


    //作用域 - 有效的
    public function scopeEffective($query)
    {
        //使用中的订单 或者 已完成且时长超过5分钟 均为有效
        return $query->where(function ($q) {
            $q->where('status', self::STATUS_END)->where('duration_seconds', '>', self::FREE_SECONDS);
        })->orWhere('status', self::STATUS_USING);
    }


    /**
     * @return string
     */
    public static function getDistributorRelatePivotTable()
    {
        return 'distributor_orders';
    }

    /**
     * @return array
     */
    public static function getDistributorRelatePivotColumns()
    {
        return ['profit'];
    }

    /**
     * @return string
     */
    public static function getDistributorRelatePivotModel()
    {
        return DistributorOrder::class;
    }

    public function needPush(){
        return Distributors::where(function($query) {
            $query->where('id', 10)
                ->orWhere('parent_id', 10);
        })->where('id', $this->distributor_id)
            ->exists();
    }

}
